`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 11/20/2024 06:49:16 PM
// Design Name: 
// Module Name: mipi
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//////////////////////////////////////////////////////////////////////////////////


module sdm_ctrl #
(
  parameter DATA_WIDTH        = 32,
  parameter ADDRESS_WIDTH     = 12
) (

  input                         fbclk       ,
  input                         sys_clk     ,

  output   [24:0]               sdm1_data   ,
  output                        sdm1_reset  ,
  output                        sdm1_toggle ,
  output   [1:0]                sdm1_width  ,
  // bus interface
  input                         up_rstn     ,
  input                         up_clk      ,

  input                         up_wreq     ,
  input    [ADDRESS_WIDTH-1:0]  up_waddr    ,
  input    [DATA_WIDTH - 1 :0]  up_wdata    ,
  output                        up_wack     ,

  input                         up_rreq     ,
  input    [ADDRESS_WIDTH-1:0]  up_raddr    ,
  output   [DATA_WIDTH - 1 :0]  up_rdata    ,
  output                        up_rack                         
);
    reg                         up_sdm1_reset              ;
    reg  [ 1:0]                 up_sdm1_width              ;
    reg  [23:0]                 up_sdm1_data  = 24'h978D4F ;

    // Cross-clock domain processing
    reg  [23:0]                 up_sdm1_data_step1 = 24'h978D4F ;
    reg  [23:0]                 up_sdm1_data_step2 = 24'h978D4F ;
    reg                         up_wreq_step1                   ; 
    reg                         up_wreq_step2                   ; 
    reg                         sdm1_toggle_reg = 1'b0          ;
    reg                         sdm1_toggle_reg_1               ;
    reg                         sdm1_toggle_reg_2               ;
    reg  [2:0]                  fbclk_cnt = 3'd0                ;
    
    always @(posedge sys_clk ) begin  
        up_sdm1_data_step1         <= up_sdm1_data              ;   
        up_sdm1_data_step2         <= up_sdm1_data_step1        ; 
        up_wreq_step1              <= up_wreq                   ;
        up_wreq_step2              <= up_wreq_step1             ;
        sdm1_toggle_reg_1          <= sdm1_toggle_reg           ;
        sdm1_toggle_reg_2          <= sdm1_toggle_reg_1         ;
    end    

    always @(posedge sys_clk) begin
        if(up_wreq_step2 && (!up_wreq_step1))
            sdm1_toggle_reg <= 1'b1;
        else if(fbclk_cnt == 3'd6)
            sdm1_toggle_reg <= 1'b0;
        else
            sdm1_toggle_reg <= sdm1_toggle_reg;
    end

    always @(posedge fbclk) begin
        if(up_wreq_step2 && (fbclk_cnt == 3'b0))
            fbclk_cnt <= fbclk_cnt + 3'd1;
        else if(fbclk_cnt != 3'b0)
            fbclk_cnt <= fbclk_cnt + 3'd1;
        else
            fbclk_cnt <= 3'd0;
    end

    // ******************************************************************************* 
    // ************************ 100 MHz up_clk clock domain processing ***************
    // ******************************************************************************* 
    // AXI to registers and bus interface
    // write data

    // processor write interface
    reg up_wack_int;
    assign up_wack = up_wack_int;
    always @(negedge up_rstn or posedge up_clk) begin
        if (up_rstn == 0) begin
            up_wack_int <= 'd0;
        end else begin
            up_wack_int <= up_wreq;
        end
    end

    always @(negedge up_rstn or posedge up_clk) begin
        if (up_rstn == 0) begin  
            up_sdm1_reset           <= 1'b0             ;      
            up_sdm1_width           <= 2'b0             ;  
            up_sdm1_data            <= 24'h978D4F       ;  //0.0592
        end else begin    
            if ((up_wreq == 1'b1) && (up_waddr[ADDRESS_WIDTH-1:2] == 14'h0)) begin
                up_sdm1_width       <= up_wdata[29:28]  ;  
                up_sdm1_reset       <= up_wdata[24]     ;  
                up_sdm1_data        <= up_wdata[23:0]   ;
            end 
        end
    end

    // read data
    reg             up_rack_int  = 'd0;
    reg     [31:0]  up_rdata_int = 'd0;
    assign up_rack  = up_rack_int   ;
    assign up_rdata = up_rdata_int  ;

    always @(negedge up_rstn or posedge up_clk) begin
        if (up_rstn == 0) begin
            up_rack_int <= 'd0;
            up_rdata_int <= 'd0;
        end else begin
            up_rack_int <= up_rreq ;
            if (up_rreq  == 1'b1) begin
                case (up_raddr[ADDRESS_WIDTH-1:2])          
                    12'h0: up_rdata_int  <=  { 2'b0, up_sdm1_width, 3'b0, up_sdm1_reset, up_sdm1_data} ;
                endcase
            end else begin
                up_rdata_int <= 32'd0;
            end
        end
    end

    // output to sdm1
    assign sdm1_reset  = up_sdm1_reset      ;
    assign sdm1_width  = up_sdm1_width      ;
    assign sdm1_data   = {1'b0, up_sdm1_data_step2} ;
    assign sdm1_toggle = sdm1_toggle_reg_2  ;

endmodule
